﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;

using System.Windows.Forms;
using System.IO;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

using OfficeOpenXml;
using System.Drawing;
using OfficeOpenXml.Style;


namespace haimian
{
    /// <summary>
    /// 海绵城市下垫面的信息类
    /// </summary>
    class HatchInfo : IComparable
    {
        // 面积
        public double Area { get; set; }
        // WCS坐标
        public Point3d WCSPosition { get; set; }
        // UCS坐标
        public Point3d UCSPosition { get; set; }
        // 块中央坐标
        public Point3d CenterPosition { get; set; }
        // 编号
        public string Id { get; set; }
        // 是否闭合
        public bool IsClosed { get; set; }
        // 是否有引线
        public bool HasLeader { get; set; }
        public HatchInfo(double area, Point3d wcsPosition, Point3d ucsPositon, Point3d centerPosition, bool isClosed)
        {
            Area = area;
            WCSPosition = wcsPosition;
            UCSPosition = ucsPositon;
            CenterPosition = centerPosition;
            IsClosed = isClosed;
        }

        /// <summary>
        /// 根据块的Y坐标降序排序
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int CompareTo(object obj)
        {
            HatchInfo h = obj as HatchInfo;
            double nextY = h.UCSPosition.Y;
            double prevY = UCSPosition.Y;

            return nextY.CompareTo(prevY);
        }
    }

    class CalloutPattlePanelViewModel: INotifyPropertyChanged
    {
        // 编号前缀
        string m_scaleSize;
        // 编号前缀
        string m_prefix;
        // 编号起始数字
        int m_startNumber;
        // 字体高度
        double m_fontHeight;
        // 是否有引线
        bool m_hasLeader;
        // 图层名称
        string m_layerName;
        readonly List<string> m_scaleList = new List<string> { "mm","m"};

        public CalloutPattlePanelViewModel()
        {
            m_prefix = "X";
            m_scaleSize = "mm";
            m_fontHeight = 500;
            m_startNumber = 1;
            m_hasLeader = true;
        }

        // 比例单位
        public string ScaleSize
        {
            get { return m_scaleSize; }
            set
            {
                if (value != m_scaleSize)
                {
                    m_scaleSize = value;
                    Notify("ScaleSize");
                }
            }
        }

        // 图层名称列表
        public ArrayList LayerList
        {
            get { return GetLayerName(); }
        }

        public string LayerName
        {
            get { return m_layerName; }
            set
            {
                if (value != m_layerName)
                {
                    m_layerName = value;
                    Notify("LayerName");
                }
            }
        }
        // 比例尺寸单位列表
        public List<string> ScaleList
        {
            get { return m_scaleList; }
        }


        // 编号前缀
        public string Prefix
        {
            get { return m_prefix; }
            set
            {
                if (value != m_prefix)
                {
                    m_prefix = value;
                    Notify("Prefix");
                }
            }
        }

        // 编号前缀
        public int StartNumber
        {
            get { return m_startNumber; }
            set
            {
                if (value != m_startNumber)
                {
                    m_startNumber = value;
                    Notify("StartNumber");
                }
            }
        }

        // 字体高度
        public double FontHeight
        {
            get { return m_fontHeight; }
            set
            {
                if (value != m_fontHeight)
                {
                    m_fontHeight = value;
                    Notify("FontHeight");
                }
            }
        }


        // 是否有引线
        public bool HasLeader
        {
            get { return m_hasLeader; }
            set
            {
                if (value != m_hasLeader)
                {
                    m_hasLeader = value;
                    Notify("HasLeader");
                }
            }
        }

        // 批量统计面积（命令）
        public RelayCommand CountAllCommand
        {
            get
            {
                return new RelayCommand((_) => GetBlockInfo(), (_) => true);
            }
        }

        // 选择需要统计的图层（命令）
        public RelayCommand GetCurrentLayerCommand
        {
            get
            {
                return new RelayCommand((_) => GetCurrentLayer(), (_) => true);
            }
        }

        // 获取所有图层的名称列表
        public ArrayList GetLayerName()
        {
            ArrayList layers = new ArrayList();
            using (Database db = HostApplicationServices.WorkingDatabase)
            {
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                    using (LayerTable lt = (LayerTable)trans.GetObject(db.LayerTableId, OpenMode.ForRead))
                    {
                        foreach (ObjectId id in lt)
                        {
                            LayerTableRecord ltr = (LayerTableRecord)trans.GetObject(id, OpenMode.ForRead);
                            layers.Add(ltr.Name);
                        }
                    }
                    trans.Commit();
                }
            }

            return layers;
        }

        // 获取图块信息
        private void GetBlockInfo()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            TypedValue[] values = new TypedValue[]
            {
                new TypedValue((int)DxfCode.Start,"HATCH"),
                new TypedValue((int)DxfCode.LayerName, LayerName),
            };

            SelectionFilter filter = new SelectionFilter(values);
            PromptSelectionResult entRes = ed.GetSelection(filter);

            //CoordinateSystem3d cs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
            //Double ucsRotation = Vector3d.XAxis.GetAngleTo(cs.Xaxis, Vector3d.ZAxis);

            CoordinateSystem3d UCS = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
            Plane OcsPlane = new Plane(Point3d.Origin, UCS.Zaxis);
            CoordinateSystem3d OCS = Matrix3d.PlaneToWorld(OcsPlane).CoordinateSystem3d;
            double ucsRotation = OCS.Xaxis.GetAngleTo(UCS.Xaxis, UCS.Zaxis);

            if (entRes.Status == PromptStatus.OK)
            {
                SelectionSet sSet = entRes.Value;

                HatchInfo[] hatches = this.GetHatch(sSet, ed);
                Array.Sort(hatches);
                int hatchLength = hatches.Length;


                //const string arrowName = "_DOT";
                //ObjectId arrId = GetArrowObjectId(arrowName);

                using (DocumentLock docLock = doc.LockDocument())
                {
                    using (Transaction trans = db.TransactionManager.StartTransaction())
                    {
                        for (int i = 0; i < hatchLength; i++)
                        {
                            string id = string.Format("{0}{1}", Prefix, StartNumber + i);
                            hatches[i].Id = id;

                            MText text = new MText();

                            text.Location = hatches[i].WCSPosition;
                            text.Rotation = ucsRotation;
                            text.Height = FontHeight;
                            text.TextHeight = FontHeight;
                            text.Contents = string.Format("{0}-{1}", hatches[i].Id, hatches[i].Area);


                            db.AddToModelSpace(text);

                            if( HasLeader == true)
                            {
                                Leader leader = new Leader();
                                leader.AppendVertex(hatches[i].CenterPosition);
                                leader.AppendVertex(hatches[i].WCSPosition);
                                db.AddToModelSpace(leader);
                                leader.ColorIndex = 3;  //设置引线的颜色为绿色
                                // 图纸的比例尺为mm的情况
                                if (m_scaleSize == "mm")
                                {
                                    leader.Dimgap = 1; //设置引线的文字偏移为1
                                    leader.Dimasz = 5;//设置引线的箭头大小为5
                                } else
                                {
                                    leader.Dimgap = 0.5; //设置引线的文字偏移为0.5
                                    leader.Dimasz = 0.5;//设置引线的箭头大小为0.5
                                }
                                leader.Annotation = text.ObjectId;//设置引线的注释对象为文本
                                //leader.Dimldrblk = arrId;
                                leader.EvaluateLeader();//计算引线及其关联注释之间的关系
                            }
                        }
                        trans.Commit();
                    }
                }
                ed.WriteMessage("已经完成{0}个对象的统计~\n", hatchLength);
                this.exportExcel(hatches);
            }
        }

        //// 根据name获取引线的箭头类型的ObjectId
        //private ObjectId GetArrowObjectId(string newArrName)
        //{

        //    ObjectId arrObjId = ObjectId.Null;

        //    Document doc = AcAp.DocumentManager.MdiActiveDocument;
        //    Database db = doc.Database;

        //    // Get the current value of DIMBLK

        //    string oldArrName = AcAp.GetSystemVariable("DIMBLK") as string;
            
        //    // Set DIMBLK to the new style
        //    // (this action may create a new block)

        //    AcAp.SetSystemVariable(
        //      "DIMBLK",
        //      newArrName
        //    );


        //    // Reset the previous value of DIMBLK

        //    if (oldArrName.Length != 0)
        //        AcAp.SetSystemVariable(
        //          "DIMBLK",
        //          oldArrName
        //        );


        //    // Now get the objectId of the block

        //    using (Transaction tr = db.TransactionManager.StartTransaction())
        //    {
        //        BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId,OpenMode.ForRead);
        //        arrObjId = bt[newArrName];
        //        tr.Commit();
        //    }
        //    return arrObjId;
        //}

        // 选择需要统计的图层
        private void GetCurrentLayer()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
/*            var ly;*/

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                PromptEntityResult entRes = ed.GetEntity("\n请点选需要统计的图层");
                if (entRes.Status == PromptStatus.OK)
                {
                    Entity ent = trans.GetObject(entRes.ObjectId, OpenMode.ForRead) as Entity;
                    if(ent != null)
                    {
                        LayerName = ent.Layer;
                        ed.WriteMessage("\n已经选择了图层：{0}\n", LayerName);
                    }
                }
                trans.Commit();
            }


        }

        /// <summary>
        /// 获取框选下的Hatch集合信息
        /// </summary>
        /// <param name="sSet">框选集合</param>
        /// <param name="ed">AutoCAD编辑器</param>
        /// <returns></returns>
        private HatchInfo[] GetHatch(SelectionSet sSet, Editor ed)
        {
            ObjectId[] ids = sSet.GetObjectIds();
            HatchInfo[] hatches = new HatchInfo[ids.Length];
            Database db = HostApplicationServices.WorkingDatabase;

            Matrix3d wcs2ucs = ed.CurrentUserCoordinateSystem.Inverse();
            CoordinateSystem3d cs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
            Double ucsRotation = Vector3d.XAxis.GetAngleTo(cs.Xaxis, Vector3d.ZAxis);

            int hatch_length = ids.Length;
            int error_length = 0;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                for (int i = 0; i < ids.Length; i++)
                {
                    Hatch ent = (Hatch)ids[i].GetObject(OpenMode.ForRead);

                    Point3d minPoint = ent.GeometricExtents.MinPoint;
                    Point3d maxPoint = ent.GeometricExtents.MaxPoint;

                    //Point3d textOriginPosition = new Point3d((minPoint.X + maxPoint.X) / 2, minPoint.Y, 0);
                    // 设置文字标注在图块的3/4的X轴方向，图块Y轴最下
                    Point3d textOriginPosition = new Point3d(minPoint.X * 0.25 + maxPoint.X * 0.75, minPoint.Y, 0);
                    // 图块的中心位置
                    Point3d entCenterPosition = new Point3d((minPoint.X + maxPoint.X) / 2, (minPoint.Y + maxPoint.Y) / 2, 0);
                    Point3d wcsPosition = textOriginPosition.TransformBy(Matrix3d.Rotation(ucsRotation, cs.Zaxis, entCenterPosition));

                    Point3d ucsPosition = wcsPosition.TransformBy(wcs2ucs);

                    double area = 0;
                    bool isClosed = true;
                    try
                    {
                        area = ent.Area;
                        if (m_scaleSize == "mm")
                        {
                            area = Math.Round(ent.Area / 1000000, 1);
                        }
                        else
                        {
                            area = Math.Round(ent.Area, 1);
                        }
                    }
                    catch
                    {
                        isClosed = false;
                        error_length++;
                    }
                    finally
                    {
                        HatchInfo hatch = new HatchInfo(area, wcsPosition, ucsPosition, entCenterPosition,isClosed);
                        hatches[i] = hatch;
                    }


                }
                if(error_length == 0)
                {
                    ed.WriteMessage("\n共有{0}填充图块，未出现错误图块\n", hatch_length);
                } else
                {
                    ed.WriteMessage("\n共有{0}填充图块，其中有{1}块错误未闭合图块\n", hatch_length, error_length);

                }
                trans.Commit();
            }
            return hatches;
        }

        /// <summary>
        /// 输出EXCEL格式的统计数据
        /// </summary>
        /// <param name="hatches"></param>
        private void exportExcel(HatchInfo[] hatches)
        {
            double areaSum = 0;

            using (ExcelPackage package = new ExcelPackage())
            {
                // Add a new worksheet to the empty workbook
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("面积汇总");
                worksheet.Cells[1, 1].Value = "编号";
                worksheet.Cells[1, 2].Value = "面积（平方米）";

                for (int i = 0; i < hatches.Length; i++)
                {
                    worksheet.Cells[i + 2, 1].Value = hatches[i].Id;
                    worksheet.Cells[i + 2, 2].Value = hatches[i].Area;
                    if (!hatches[i].IsClosed)
                    {
                        worksheet.Cells[i + 2, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
                        worksheet.Cells[i + 2, 1].Style.Fill.BackgroundColor.SetColor(Color.OrangeRed);
                    }
                    areaSum += hatches[i].Area;
                }
                worksheet.Cells[hatches.Length + 2, 1].Value = "合计";
                worksheet.Cells[hatches.Length + 2, 2].Value = Math.Round(areaSum, 1);

                string localFilePath = @"D:\面积统计.xlsx";

                try
                {
                    // 调用一个系统自带的保存文件对话框 写一个EXCEL
                    SaveFileDialog saveFileDialog = new SaveFileDialog();   //新建winform自带保存文件对话框对象
                    saveFileDialog.Filter = "Excel Office2007及以上(*.xlsx)|*.xlsx|Excel Office97-2003(*.xls)|*.xls";  //过滤只能存储的对象
                    DialogResult result = saveFileDialog.ShowDialog();     //显示对话框
                    localFilePath = saveFileDialog.FileName.ToString();
                    FileInfo xlFile = new FileInfo(localFilePath);
                    package.SaveAs(xlFile);
                }
                catch
                {
                }


            }

        }


        // 数据绑定相关
        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify(string propertyName)
        {
            if (PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
